<template>
  <n-form label-width="60" label-align="left" v-bind="formProps">
    <n-grid :cols="basicTotalSpans" :x-gap="24" :y-gap="0" v-bind="gridProps">
      <n-form-item-gi
        v-for="item in filterOptions"
        :key="item.key"
        :span="item.span || basicSpans"
        :label="item.label"
        label-placement="left"
        :label-style="{
          whiteSpace: 'pre-wrap',
          wordBreak: 'break-all'
        }"
      >
        <n-date-picker
          v-if="item.type === 'NDatePicker' && (item.originPros as DatePickerProps).valueFormat"
          v-model:formatted-value="modelValue[item.key]"
          clearable
          style="width: 100%"
          v-bind="(item as any).originPros"
        ></n-date-picker>
        <component
          v-else
          :is="getComponent(item.type)"
          v-model:value="modelValue[item.key]"
          clearable
          v-bind="item.originPros"
        ></component>
      </n-form-item-gi>
      <n-form-item-gi :span="operateBtnSpans" label="" label-placement="left">
        <n-space justify="end" style="width: 100%">
          <n-button @click="reset">重置</n-button>
          <n-button type="primary" @click="search">筛选</n-button>
        </n-space>
      </n-form-item-gi>
    </n-grid>
  </n-form>
</template>

<script setup lang="ts">
import {
  NInput,
  InputProps,
  NSelect,
  SelectProps,
  NDatePicker,
  DatePickerProps,
  NTreeSelect,
  TreeSelectProps,
  NCascader,
  CascaderProps,
  FormProps,
  GridProps
} from 'naive-ui'

type ComponentType = 'NInput' | 'NSelect' | 'NTreeSelect' | 'NCascader' | 'NDatePicker'

export type FilterItem = {
  /** 名称 */
  label?: string
  /** 键名 */
  key: string
  /** 组件类型 */
  type: ComponentType
  /** 占位 */
  span?: number
  /** 组件原生属性 */
  originPros?: InputProps | SelectProps | DatePickerProps | TreeSelectProps | CascaderProps
}

const props = defineProps<{
  filterOptions: Array<FilterItem>
  /** 表单原生属性 */
  formProps?: FormProps
  /** 布局原生属性 */
  gridProps?: GridProps
}>()
const emit = defineEmits<{
  (e: 'search', val: any): void
}>()

/** 栅栏基数列 */
const basicTotalSpans = 12
/** 默认占4列 */
const basicSpans = 4

/** 筛选组绑定值 */
const modelValue = ref<any>({})

/** 根据筛选项内容计算操作按钮占比 */
const operateBtnSpans = computed(() => {
  const { filterOptions } = props
  /** 最后一项是否占满了, 占满了则操作栏直接占满一行 */
  const lastItemIsFill =
    filterOptions[filterOptions.length - 1]?.span === basicTotalSpans ? true : false
  if (lastItemIsFill) return basicTotalSpans
  /** 找到最后一项占满一行的下标 */
  const index = filterOptions.findLastIndex((k) => k?.span === basicTotalSpans)
  /** 最后一行已占据的spans数 */
  let totalNum = 0
  /** 计算最后一行已占据的spans数 */
  filterOptions.slice(index).forEach((cur) => {
    const curSpan = cur?.span ? cur.span : basicSpans
    totalNum = totalNum + curSpan

    /** 占满时重置清零 */
    if (totalNum === basicTotalSpans) {
      totalNum = 0
    }

    /** 超出时，总量重置为下一个值 */
    if (totalNum > basicTotalSpans) {
      totalNum = curSpan
    }
  })

  /** 最后一行有空余则返回剩余的，无则新启一行 */
  return basicTotalSpans - totalNum
})

/** 重置 */
function reset() {
  Object.keys(modelValue.value).forEach((k) => {
    modelValue.value[k] = null
  })
  emit('search', modelValue.value)
}

/** 重置 */
function search() {
  emit('search', modelValue.value)
}

/** 获取对应筛选组件 */
function getComponent(type: ComponentType) {
  switch (type) {
    case 'NInput':
      return NInput
    case 'NSelect':
      return NSelect
    case 'NDatePicker':
      return NDatePicker
    case 'NTreeSelect':
      return NTreeSelect
    case 'NCascader':
      return NCascader
    default:
      return null
  }
}
</script>

<style lang="less" scoped></style>
